package AICore.Engine;

import game.GameBoard;
import game.Player;

import java.util.LinkedList;

import AICore.ActionScore;
import AICore.GameState;
import AICore.SolutionsFactory;

import carddeck.Card;
import carddeck.Rank;
import carddeck.Suit;

public class AIEngineUnit {
	//AIEnginePlay
	AIEnginePlay disaPlayEngine;
	AIEnginePlay tiedPlayEngine;
	AIEnginePlay advaPlayEngine;
	AIEnginePlay calmPlayEngine;
	
	//AIEngineDemand
	AIEngineDemander disaDemandEngine;
	AIEngineDemander tiedDemandEngine;
	AIEngineDemander advaDemandEngine;
	AIEngineDemander calmDemandEngine;
	
	//AIEngineColorChanger
	AIEngineColorChanger disaColChEngine;
	AIEngineColorChanger tiedColChEngine;
	AIEngineColorChanger advaColChEngine;
	AIEngineColorChanger calmColChEngine;
	
	//the game
	Suit bestColor;
	Player playerOwner;
	LinkedList<Card> bestSolution;
	LinkedList<LinkedList<Card>> solutions;
	LinkedList<Suit> otherBestColors;
	LinkedList<Suit> forbiddenColors;
	LinkedList<Rank> forbiddenRanks;
	LinkedList<Suit> nextForbiddenColors;
	Rank nextForbiddenRank;
	
	Suit patternSuit;
	Rank patternRank;
	
	//stats stuff
	int patternWins;
	boolean bJustPlayedPattern;
	boolean bAfterpattern;
	int patternMoves;
	
	protected GameState gameState;
	
	public AIEngineUnit(Player owner) {
		playerOwner = owner;
		gameState=null;
		otherBestColors=null;
		bestColor=null;
		forbiddenColors=new LinkedList<>();
		forbiddenRanks = new LinkedList<>();
		nextForbiddenColors= new LinkedList<>();
		nextForbiddenRank = null;
		bestSolution = null;
		patternSuit = null;
		patternRank = null;
		patternWins = 0;
		patternMoves = 0;
		bJustPlayedPattern=false;
		bAfterpattern=false;
		createBestAI();
	}
	public AIEngineUnit(Player owner, boolean Alternative) {
		playerOwner = owner;
		gameState=null;
		otherBestColors=null;
		bestColor=null;
		forbiddenColors=new LinkedList<>();
		forbiddenRanks = new LinkedList<>();
		nextForbiddenColors= new LinkedList<>();
		nextForbiddenRank = null;
		bestSolution = null;
		patternSuit = null;
		patternRank = null;
		patternWins = 0;
		bJustPlayedPattern=false;
		bAfterpattern=false;
		if(Alternative)
			createAlternativeAI();
		else
			createBestAI();
	}
	
	private void createBestAI() {
		disaPlayEngine = new AIEnginePlayTied(this);
		tiedPlayEngine = new AIEnginePlayTied(this);
		advaPlayEngine = new AIEnginePlayTied(this);
		calmPlayEngine = new AIEnginePlayCalm(this);

		disaDemandEngine = new AIEngineDemanderCalm(this);
		tiedDemandEngine = new AIEngineDemanderCalm(this);
		advaDemandEngine = new AIEngineDemanderCalm(this);
		calmDemandEngine = new AIEngineDemanderCalm(this);
		
		disaColChEngine = new AIEngineColorChangerCalm(this);
		tiedColChEngine = new AIEngineColorChangerCalm(this);
		advaColChEngine = new AIEngineColorChangerCalm(this);
		calmColChEngine = new AIEngineColorChangerCalm(this);
	}
	
	private void createAlternativeAI() {
		disaPlayEngine = new AIEnginePlayTied2(this);
		tiedPlayEngine = new AIEnginePlayTied(this);
		advaPlayEngine = new AIEnginePlayTied2(this);
		calmPlayEngine = new AIEnginePlayCalm(this);

		disaDemandEngine = new AIEngineDemanderCalm(this);
		tiedDemandEngine = new AIEngineDemanderCalm(this);
		advaDemandEngine = new AIEngineDemanderCalm(this);
		calmDemandEngine = new AIEngineDemanderCalm(this);
		
		disaColChEngine = new AIEngineColorChangerCalm(this);
		tiedColChEngine = new AIEngineColorChangerCalm(this);
		advaColChEngine = new AIEngineColorChangerCalm(this);
		calmColChEngine = new AIEngineColorChangerCalm(this);
	}
	
	public void makeAMove(boolean bAfterdraw) {
		resetEngine();
		if(bAfterdraw)
			solutions = SolutionsFactory.createSolutions(playerOwner.getAllCards(), GameBoard.getInstance().getCardRevealed(), null);
		else
			solutions = SolutionsFactory.createSolutions(playerOwner.getCards(), null, null);
		
		switch(gameState) {
		case GS_DISADVANTAGE:
			disaPlayEngine.makeAMove(bAfterdraw);
			break;
		case GS_TIED:
			//TODO its just a test
			//tiedPlayEngine.makeAMove(bAfterdraw);
			advaPlayEngine.makeAMove(bAfterdraw);
			break;
		case GS_ADVANTAGE:
			advaPlayEngine.makeAMove(bAfterdraw);
			break;
		case GS_CALM:
			calmPlayEngine.makeAMove(bAfterdraw);
			break;
		default:
			calmPlayEngine.makeAMove(bAfterdraw);
		}
	}
	public void makeADemand() {
		if(patternRank!=null) {
			playerOwner.demand(patternRank);
			patternRank=null;
			return;
		}
		switch(gameState) {
		case GS_DISADVANTAGE:
			disaDemandEngine.makeADemand();
			break;
		case GS_TIED:
			tiedDemandEngine.makeADemand();
			break;
		case GS_ADVANTAGE:
			advaDemandEngine.makeADemand();
			break;
		case GS_CALM:
			calmDemandEngine.makeADemand();
			break;
		default:
			calmDemandEngine.makeADemand();
		}
	}
	public ActionScore considerColorChange(LinkedList<LinkedList<Card>> solutions, boolean bAceChange) {
		switch(gameState) {
		case GS_DISADVANTAGE:
			return disaColChEngine.considerColorChange(solutions, bAceChange);
		case GS_TIED:
			return tiedColChEngine.considerColorChange(solutions, bAceChange);
		case GS_ADVANTAGE:
			return advaColChEngine.considerColorChange(solutions, bAceChange);
		case GS_CALM:
			return calmColChEngine.considerColorChange(solutions, bAceChange);
		default:
			return calmColChEngine.considerColorChange(solutions, bAceChange);
		}
	}
	
	public void pickAColor(Card theAce) {
		if(patternSuit!=null) {
			theAce.setFakeCard(new Card(patternSuit, Rank.ACE));
			patternSuit=null;
		}
		switch(gameState) {
		case GS_DISADVANTAGE:
			disaColChEngine.pickAColor(theAce);
			break;
		case GS_TIED:
			tiedColChEngine.pickAColor(theAce);
			break;
		case GS_ADVANTAGE:
			advaColChEngine.pickAColor(theAce);
			break;
		case GS_CALM:
			calmColChEngine.pickAColor(theAce);
			break;
		default:
			calmColChEngine.pickAColor(theAce);
			break;
		}
	}
	
	private void resetEngine() {
		bestColor=null;
		forbiddenColors.clear();
		forbiddenRanks.clear();
		nextForbiddenColors.clear();
		nextForbiddenRank=null;
		gameState = GameBoard.getInstance().computeGameStateFor(playerOwner);
		solutions = null;
		bestSolution = null;
		patternSuit = null;
		patternRank = null;
		bAfterpattern=bJustPlayedPattern;
		bJustPlayedPattern=false;
	}
	
	public String statsString() {
		return "Pattern moves: "+patternMoves+". PatternWins: "+patternWins+". ";
	}
}
